<template>
  <div class="streams-container">
    <el-card>
      <template #header>
        <div class="card-header">
          <span>直播流管理</span>
          <el-button type="primary" @click="refreshStreams" style="margin-right: 10px;">
            <el-icon><Refresh /></el-icon>
            刷新
          </el-button>
          <el-button type="success" @click="showConfigDialog = true">
            配置域名
          </el-button>
        </div>
      </template>

      <div class="search-bar">
        <el-input
            v-model="searchQuery"
            placeholder="搜索流名称或应用名"
            prefix-icon="Search"
            clearable
            style="width: 300px; margin-right: 12px"
        />
        <el-button type="primary" @click="handleSearch">搜索</el-button>
        <el-button @click="resetSearch">重置</el-button>
      </div>

      <el-table
          v-loading="loading"
          :data="filteredStreams"
          style="width: 100%; margin-top: 16px"
          border
          :row-clickable="false"
      >
        <el-table-column type="index" label="#" width="60" />
        <el-table-column prop="app" label="应用名" min-width="100" />
        <el-table-column prop="name" label="流名称" min-width="200">
          <template #default="scope">
            <el-tag>{{ scope.row.name }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="clients" label="客户端数" min-width="100" />
        <el-table-column prop="frames" label="帧数" min-width="100" />
        <el-table-column prop="live_ms" label="推流时间" min-width="180">
          <template #default="scope">
            {{ formatDuration(scope.row.live_ms) }}
          </template>
        </el-table-column>
        <el-table-column prop="video" label="视频信息" min-width="180">
          <template #default="scope">
            <div v-if="scope.row.video && scope.row.video.codec">
              {{ scope.row.video.codec }} / {{ scope.row.video.width }}x{{ scope.row.video.height }}
            </div>
            <span v-else>--</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" min-width="200" fixed="right">
          <template #default="scope">
            <el-button
                type="primary"
                size="small"
                @click="viewStreamDetail(scope.row)"
                style="margin-right: 8px"
            >
              详情
            </el-button>
            <el-button
                type="danger"
                size="small"
                @click="confirmCloseStream(scope.row)"
            >
              关闭流
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <div class="pagination" v-if="!loading">
        <el-pagination
            v-model:current-page="currentPage"
            v-model:page-size="pageSize"
            :page-sizes="[10, 20, 50, 100]"
            layout="total, sizes, prev, pager, next, jumper"
            :total="streams.length"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
        />
      </div>
    </el-card>

    <el-dialog
        v-model="detailVisible"
        title="直播流详情"
        width="600px"
        :before-close="closeDetailDialog"
    >
      <div v-if="selectedStream">

        <h4 style="margin-top: 20px; margin-bottom: 10px;">直播画面预览</h4>
        <div v-if="flvPlayUrl">
          <video
              ref="flvPlayerRef"
              controls
              autoplay
              style="width: 100%; max-height: 400px; background-color: #000;"
          ></video>
        </div>
        <div v-else style="color: #e6a23c; margin-top: 10px;">
          无法预览，请配置 FLV 服务器域名。
        </div>

        <el-descriptions :column="1" border>
          <el-descriptions-item label="流标识">
            {{ selectedStream.app }}/{{ selectedStream.name }}
          </el-descriptions-item>
          <el-descriptions-item label="推流URL">
            {{ selectedStream.tcUrl }}
          </el-descriptions-item>

          <el-descriptions-item label="播放地址 (HLS)">
            <el-tag v-if="streamConfig.hlsDomain" type="info">{{ hlsPlayUrl }}</el-tag>
            <div v-else>请配置HLS服务器域名</div>
          </el-descriptions-item>

          <el-descriptions-item label="播放地址 (FLV)">
            <el-tag v-if="streamConfig.flvDomain" type="info">{{ flvPlayUrl }}</el-tag>
            <div v-else>请配置FLV服务器域名</div>
          </el-descriptions-item>

          <el-descriptions-item label="推流时间">
            {{ formatDuration(selectedStream.live_ms) }}
          </el-descriptions-item>
          <el-descriptions-item label="当前客户端数">
            {{ selectedStream.clients || 0 }}
          </el-descriptions-item>
          <el-descriptions-item label="上传带宽(kbps)">
            {{ selectedStream.kbps?.send_30s || 0 }}
          </el-descriptions-item>
          <el-descriptions-item label="下载带宽(kbps)">
            {{ selectedStream.kbps?.recv_30s || 0 }}
          </el-descriptions-item>
        </el-descriptions>
        <h4 style="margin-top: 20px; margin-bottom: 10px;">视频信息</h4>
        <el-descriptions :column="2" border v-if="selectedStream.video">
          <el-descriptions-item label="编码">
            {{ selectedStream.video.codec }}
          </el-descriptions-item>
          <el-descriptions-item label="分辨率">
            {{ selectedStream.video.width }}x{{ selectedStream.video.height }}
          </el-descriptions-item>
          <el-descriptions-item label="Profile">
            {{ selectedStream.video.profile || '--' }}
          </el-descriptions-item>
          <el-descriptions-item label="Level">
            {{ selectedStream.video.level || '--' }}
          </el-descriptions-item>
        </el-descriptions>

        <h4 style="margin-top: 20px; margin-bottom: 10px;">音频信息</h4>
        <el-descriptions :column="2" border v-if="selectedStream.audio">
          <el-descriptions-item label="编码">
            {{ selectedStream.audio.codec }}
          </el-descriptions-item>
          <el-descriptions-item label="采样率(Hz)">
            {{ selectedStream.audio.sample_rate }}
          </el-descriptions-item>
          <el-descriptions-item label="声道数">
            {{ selectedStream.audio.channel }}
          </el-descriptions-item>
          <el-descriptions-item label="Profile">
            {{ selectedStream.audio.profile || '--' }}
          </el-descriptions-item>
        </el-descriptions>
      </div>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="closeDetailDialog">关闭</el-button>
          <el-button type="danger" @click="confirmCloseStream(selectedStream)">
            关闭直播流
          </el-button>
        </span>
      </template>
    </el-dialog>

    <el-dialog v-model="showConfigDialog" title="配置直播服务器域名" width="600px">
      <el-form label-width="120px" :model="streamConfig">

        <el-form-item label="播放协议">
          <el-select v-model="streamConfig.protocol" placeholder="选择协议" style="width: 100%">
            <el-option label="HTTPS" value="https" />
            <el-option label="HTTP" value="http" />
          </el-select>
        </el-form-item>

        <el-form-item label="服务器域名">
          <el-input
              v-model="streamConfig.domain"
              placeholder="请输入服务器域名/IP，如 live.example.com"
              clearable
          />
        </el-form-item>

        <el-form-item label="端口 (可选)">
          <el-input
              v-model="streamConfig.port"
              placeholder="留空则使用默认端口（HTTP: 80, HTTPS: 443）"
              clearable
          />
        </el-form-item>

        <el-form-item>
          <div class="tips">
            <p>提示：</p>
            <p>1. 域名配置将保存在本地浏览器中</p>
            <p>2. 服务器域名用于构造 HLS/FLV 播放地址。</p>
            <p>3. Vhost 用于构造关闭流的请求体。</p>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
      <span class="dialog-footer">
        <el-button @click="showConfigDialog = false">取消</el-button>
        <el-button type="primary" @click="saveStreamConfig">保存配置</el-button>
      </span>
      </template>
    </el-dialog>

    <el-dialog v-model="confirmVisible" title="确认关闭直播流" width="400px">
      <div v-if="streamToClose">
        <p>
          确定要关闭直播流
          <strong>{{ streamToClose.app }}/{{ streamToClose.name }}</strong> 吗？
        </p>
        <p style="color: #f56c6c; margin-top: 10px;">
          注意：关闭流后，所有观看此流的客户端将断开连接。
        </p>
      </div>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="confirmVisible = false">取消</el-button>
          <el-button type="danger" @click="closeStream">确认关闭</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import {computed, onBeforeUnmount, onMounted, ref, watch} from 'vue'
import {Refresh} from '@element-plus/icons-vue'
import {ElMessage} from 'element-plus'

const loading = ref(false)
const searchQuery = ref('')
const streams = ref([])
const currentPage = ref(1)
const pageSize = ref(10)
const detailVisible = ref(false)
const confirmVisible = ref(false)
const showConfigDialog = ref(false)
const selectedStream = ref(null)
const streamToClose = ref(null)

// 【FLV 播放器相关的引用】
const flvPlayerRef = ref(null)
let flvPlayerInstance = null // FLV 播放器实例

// 默认流配置
const DEFAULT_STREAM_CONFIG = {
  protocol: 'http',
  domain: 'live.example.cn',
  port: '8080'
}

// 流配置
const streamConfig = ref({ ...DEFAULT_STREAM_CONFIG })

// 从localStorage加载配置
const loadStreamConfig = () => {
  try {
    const savedConfig = localStorage.getItem('streamConfig')
    if (savedConfig) {
      streamConfig.value = { ...DEFAULT_STREAM_CONFIG, ...JSON.parse(savedConfig) }
    }
  } catch (error) {
    console.error('加载流配置失败:', error)
    streamConfig.value = { ...DEFAULT_STREAM_CONFIG }
  }
}

// 获取直播流列表
const getStreams = async () => {
  loading.value = true
  try {
    const res = await fetch('/api/v1/streams/')
    const data = await res.json()
    if (data.code === 0 && Array.isArray(data.streams)) {
      streams.value = data.streams
    } else {
      ElMessage.error('获取直播流失败')
    }
  } catch (err) {
    console.error('获取直播流失败:', err)
    ElMessage.error('网络错误，请检查连接')
  } finally {
    loading.value = false
  }
}

// 刷新
const refreshStreams = () => {
  currentPage.value = 1
  getStreams()
}

// 【FLV 播放器相关函数】
// 销毁 FLV 播放器实例
const destroyFlvPlayer = () => {
  if (flvPlayerInstance) {
    flvPlayerInstance.destroy()
    flvPlayerInstance = null
    console.log('FLV 播放器已销毁')
  }
}

// 初始化 FLV 播放器
const initFlvPlayer = (url) => {
  destroyFlvPlayer() // 确保在创建新实例前销毁旧实例

  // 检查 flvjs 是否存在且支持 FLV 播放
  if (!window.flvjs || !window.flvjs.isSupported() || !flvPlayerRef.value) {
    if (flvPlayerRef.value) {
      flvPlayerRef.value.innerText = '浏览器不支持 FLV 播放或 flv.js 未加载。'
    }
    console.warn('FLV 播放不支持或 video 元素未准备好/flv.js未加载。')
    return
  }

  if (url) {
    flvPlayerInstance = window.flvjs.createPlayer({
      type: 'flv',
      url: url,
      isLive: true,
      cors: true, // 启用跨域请求
    }, {
      // 播放器配置
      lazyLoad: false,
      enableStashBuffer: false,
      stashInitialSize: 128
    })

    flvPlayerInstance.attachMediaElement(flvPlayerRef.value)

    flvPlayerInstance.load()
    // 尝试播放 (由于浏览器限制，可能需要用户互动，我们添加了 autoplay muted)
    flvPlayerRef.value.play().catch(e => {
      // console.log('自动播放失败:', e)
    })

    // 监听错误
    flvPlayerInstance.on(window.flvjs.Events.ERROR, (e) => {
      console.error('FLV 播放错误:', e)
      ElMessage.error(`FLV 播放失败: ${e.code || e.type}`)
    })

    console.log('FLV 播放器已初始化，URL:', url)
  }
}
// 【FLV 播放器相关函数结束】

// 格式化流URL
const formatStreamUrl = (type, config, stream) => {
  if (!config || !config.domain || !stream) return ''
  
  const { protocol, domain, port } = config
  const streamName = stream.name.replace(/\s+/g, '_') // 清理流名称
  
  // 处理默认端口
  let portStr = ''
  if (port) {
    portStr = `:${port}`
  } else if (protocol === 'https' && port !== 443) {
    portStr = ':443'
  } else if (protocol === 'http' && port !== 80) {
    portStr = ':80'
  }
  
  // 根据类型生成不同的URL
  if (type === 'hls') {
    return `${protocol}://${domain}${portStr}/live/${streamName}.m3u8`
  } else if (type === 'flv') {
    return `${protocol}://${domain}${portStr}/live/${streamName}.flv`
  }
  
  return ''
}

const hlsPlayUrl = computed(() => {
  if (!selectedStream.value || !streamConfig.value.domain) return ''
  return formatStreamUrl('hls', streamConfig.value, selectedStream.value)
})

const flvPlayUrl = computed(() => {
  if (!selectedStream.value || !streamConfig.value.domain) return ''
  return formatStreamUrl('flv', streamConfig.value, selectedStream.value)
})


// 【监听器】
watch(detailVisible, (newVal) => {
  if (!newVal) {
    // 关闭对话框时销毁播放器
    destroyFlvPlayer()
  } else {
    // 延迟确保 DOM 元素 (video) 已渲染
    setTimeout(() => {
      if (flvPlayUrl.value) {
        initFlvPlayer(flvPlayUrl.value)
      }
    }, 100)
  }
})

watch(flvPlayUrl, (newUrl) => { // 监听 flvPlayUrl 变化
  // 仅当详情对话框可见时，才在 URL 变化时初始化播放器
  if (detailVisible.value && newUrl) {
    initFlvPlayer(newUrl)
  } else if (!newUrl) {
    destroyFlvPlayer()
  }
})
// 【监听器结束】

// 查看详情
const viewStreamDetail = (stream) => {
  selectedStream.value = stream
  detailVisible.value = true
}

// 确认关闭
const confirmCloseStream = (stream) => {
  streamToClose.value = stream
  confirmVisible.value = true
}

// 关闭直播流
const closeStream = async () => {
  if (!streamToClose.value) return
  
  try {
    const res = await fetch(`/api/v1/streams/${streamToClose.value.app}/${streamToClose.value.name}`, {
      method: 'DELETE',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        vhost: '__defaultVhost__'
      })
    })
    
    if (res.ok) {
      ElMessage.success(`流 ${streamToClose.value.app}/${streamToClose.value.name} 已关闭`)
      confirmVisible.value = false
      getStreams() // 刷新流列表
    } else {
      ElMessage.error('关闭流失败')
    }
  } catch (err) {
    console.error('关闭流失败:', err)
    ElMessage.error('网络错误，请检查连接')
  } finally {
    streamToClose.value = null
  }
}

// 保存流配置
const saveStreamConfig = () => {
  if (!streamConfig.value.domain) {
    ElMessage.warning('请输入服务器域名')
    return
  }
  try {
    localStorage.setItem('streamConfig', JSON.stringify(streamConfig.value))
    ElMessage.success('配置已保存')
    showConfigDialog.value = false
  } catch (error) {
    console.error('保存配置失败:', error)
    ElMessage.error('保存配置失败')
  }
}

const closeDetailDialog = () => {
  // 确保在关闭详情对话框时销毁播放器
  destroyFlvPlayer()

  detailVisible.value = false
  selectedStream.value = null
}

// 搜索 + 分页
const handleSearch = () => (currentPage.value = 1)
const resetSearch = () => {
  searchQuery.value = ''
  currentPage.value = 1
}
const handleSizeChange = (size) => (pageSize.value = size)
const handleCurrentChange = (page) => (currentPage.value = page)

// 格式化推流时长 (ms -> H:M:S)
const formatDuration = (ms) => {
  if (!ms || ms < 0) return '--'
  const totalSeconds = Math.floor(ms / 1000);
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  const seconds = totalSeconds % 60;

  const pad = (num) => String(num).padStart(2, '0');

  // 只显示非零或必要的单位
  if (hours > 0) {
    return `${hours}小时${pad(minutes)}分${pad(seconds)}秒`;
  } else if (minutes > 0) {
    return `${minutes}分${pad(seconds)}秒`;
  } else {
    return `${seconds}秒`;
  }
}

// 过滤+分页
const filteredStreams = computed(() => {
  let result = streams.value
  if (searchQuery.value) {
    const query = searchQuery.value.toLowerCase()
    result = result.filter(
        (s) => s.name.toLowerCase().includes(query) || s.app.toLowerCase().includes(query)
    )
  }
  const start = (currentPage.value - 1) * pageSize.value
  return result.slice(start, start + pageSize.value)
})

onMounted(() => {
  // 加载配置
  loadStreamConfig()

  getStreams()
  // 每15秒自动刷新
  setInterval(() => getStreams(), 15000)
})

onBeforeUnmount(() => {
  // 确保组件卸载时销毁播放器
  destroyFlvPlayer()
})
</script>

<style scoped>
.streams-container {
  display: flex;
  flex-direction: column;
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.search-bar {
  display: flex;
  align-items: center;
  margin-bottom: 16px;
}
.pagination {
  margin-top: 20px;
  display: flex;
  justify-content: flex-end;
}
.dialog-footer {
  text-align: right;
}

.tips {
  background-color: #f0f9ff;
  border: 1px solid #b3d8ff;
  border-radius: 4px;
  padding: 10px;
  margin-top: 10px;
}

.tips p {
  margin: 5px 0;
  color: #606266;
  font-size: 14px;
}

.tips p:first-child {
  font-weight: bold;
  color: #409eff;
}
</style>